{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import print_function, division\n",
    "import tensorflow as tf\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.model_selection import train_test_split\n",
    "import random"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 切分数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def split_data(path, clients_num):\n",
    "    # 读取数据\n",
    "    data = pd.read_csv(path)\n",
    "    # 拆分数据\n",
    "    X_train, X_test, y_train, y_test = train_test_split(\n",
    "        data[[\"Temperature\", \"Humidity\", \"Light\", \"CO2\", \"HumidityRatio\"]].values,\n",
    "        data[\"Occupancy\"].values.reshape(-1, 1),\n",
    "        random_state=42)\n",
    "    \n",
    "    # one-hot 编码\n",
    "    y_train = np.concatenate([1 - y_train, y_train], 1)\n",
    "    y_test = np.concatenate([1 - y_test, y_test], 1)\n",
    "    \n",
    "    # 训练集划分给多个client\n",
    "    X_train = np.array_split(X_train, clients_num)\n",
    "    y_train = np.array_split(y_train, clients_num)\n",
    "    return X_train, X_test, y_train, y_test\n",
    "\n",
    "CLIENT_NUM = 6\n",
    "X_train, X_test, y_train, y_test = split_data(\"./data/datatraining.txt\", CLIENT_NUM)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 模拟一个储存服务\n",
    "1. Client请求最新的全局模型、以及epoch\n",
    "2. Client上传一次模型更新（epoch为参数）\n",
    "3. Server获取所有模型更新（epoch为参数）\n",
    "4. Server上传新的全局模型（epoch为参数）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import pickle\n",
    "import gzip\n",
    "\n",
    "BASE_DIR = \"./storage\"\n",
    "\n",
    "if not os.path.isdir(BASE_DIR):\n",
    "    os.mkdir(BASE_DIR)\n",
    "\n",
    "def pack(model):\n",
    "    pkl = pickle.dumps(model)\n",
    "    pkl = gzip.compress(pkl)\n",
    "    return pkl\n",
    "\n",
    "\n",
    "def unpack(data):\n",
    "    pkl = gzip.decompress(data)\n",
    "    model = pickle.loads(pkl)\n",
    "    return model\n",
    "\n",
    "\n",
    "def client_query_model():\n",
    "    \"\"\"return the newest model and epoch num\"\"\"\n",
    "    \n",
    "    newest_epoch = -1\n",
    "    res_f = None\n",
    "    \n",
    "    for f in os.listdir(BASE_DIR):\n",
    "        if not f.startswith('global_model'):\n",
    "            continue\n",
    "        file_name = os.path.splitext(f)[0]\n",
    "        epoch = int(file_name.split('_')[-1])\n",
    "        \n",
    "        if epoch > newest_epoch:\n",
    "            newest_epoch = epoch\n",
    "            res_f = f\n",
    "    \n",
    "    # file found\n",
    "    with open(\"{}/{}\".format(BASE_DIR, res_f), 'rb') as rf:\n",
    "        res = rf.read()\n",
    "    \n",
    "    return unpack(res), newest_epoch\n",
    "\n",
    "\n",
    "def client_upload_one_update(update, epoch, c_id):\n",
    "    \"\"\"upload one model update\"\"\"\n",
    "    \n",
    "    file_name = \"{}/local_update_{}_{}.ieen\".format(BASE_DIR, c_id, epoch)\n",
    "    data = pack(update)\n",
    "    \n",
    "    with open(file_name, 'wb') as wf:\n",
    "        wf.write(data)\n",
    "    \n",
    "    return\n",
    "\n",
    "\n",
    "def server_query_updates(cur_epoch):\n",
    "    \"\"\"query all model updates\"\"\"\n",
    "    \n",
    "    res = []\n",
    "    \n",
    "    for f in os.listdir(BASE_DIR):\n",
    "        if not f.startswith('local_update'):\n",
    "            continue\n",
    "        file_name = os.path.splitext(f)[0]\n",
    "        epoch = int(file_name.split('_')[-1])\n",
    "        \n",
    "        if epoch == cur_epoch:\n",
    "            with open(\"{}/{}\".format(BASE_DIR, f), 'rb') as rf:\n",
    "                data = unpack(rf.read())\n",
    "                res.append(data)\n",
    "    \n",
    "    return res\n",
    "\n",
    "\n",
    "def server_upload_model(model, epoch):\n",
    "    \"\"\"upload one model with epoch num\"\"\"\n",
    "    \n",
    "    file_name = \"{}/global_model_{}.ieen\".format(BASE_DIR, epoch)\n",
    "    data = pack(model)\n",
    "    \n",
    "    with open(file_name, 'wb') as wf:\n",
    "        wf.write(data)\n",
    "        \n",
    "    return"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Client训练获得梯度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# client 要训练的epoch\n",
    "client_epoch = [0] * CLIENT_NUM\n",
    "client_learning_rate = 0.001\n",
    "\n",
    "def train_model(client_id):\n",
    "    model, epoch = client_query_model()\n",
    "    if epoch < client_epoch[client_id]:\n",
    "        return\n",
    "    \n",
    "    tf.compat.v1.reset_default_graph()\n",
    "    \n",
    "    n_samples = X_train[client_id].shape[0]\n",
    "    \n",
    "    x = tf.placeholder(tf.float32, [None, n_features])\n",
    "    y = tf.placeholder(tf.float32, [None, n_class])\n",
    "    \n",
    "    ser_W, ser_b = model\n",
    "    W = tf.Variable(ser_W)\n",
    "    b = tf.Variable(ser_b)\n",
    "\n",
    "    pred = tf.matmul(x, W) + b\n",
    "\n",
    "    # 定义损失函数\n",
    "    cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=pred, labels=y))\n",
    "\n",
    "    # 梯度下降\n",
    "#     optimizer = tf.train.AdamOptimizer(learning_rate)\n",
    "    optimizer = tf.train.GradientDescentOptimizer(client_learning_rate)\n",
    "    \n",
    "    gradient = optimizer.compute_gradients(cost)\n",
    "    train_op = optimizer.apply_gradients(gradient)\n",
    "\n",
    "    # 初始化所有变量\n",
    "    init = tf.global_variables_initializer()\n",
    "\n",
    "    # 训练模型\n",
    "    with tf.Session() as sess:\n",
    "        sess.run(init)\n",
    "        \n",
    "        avg_cost = 0\n",
    "        total_batch = int(n_samples / batch_size)\n",
    "        for i in range(total_batch):\n",
    "            _, c = sess.run(\n",
    "                [train_op, cost],\n",
    "                feed_dict={\n",
    "                    x: X_train[client_id][i * batch_size:(i + 1) * batch_size],\n",
    "                    y: y_train[client_id][i * batch_size:(i + 1) * batch_size, :]\n",
    "                })\n",
    "            avg_cost += c / total_batch\n",
    "    \n",
    "        # 获取更新量\n",
    "        val_W, val_b = sess.run([W, b])\n",
    "    \n",
    "    delta_W = (ser_W-val_W)/client_learning_rate\n",
    "    delta_b = (ser_b-val_b)/client_learning_rate\n",
    "    delta_model = [delta_W, delta_b]\n",
    "    meta = [n_samples, avg_cost]\n",
    "    \n",
    "    client_upload_one_update([delta_model, meta], epoch, client_id)\n",
    "    \n",
    "    client_epoch[client_id] = epoch\n",
    "    return"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Server端更新模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 000, cost: 44.17, test_acc: 0.9047\n",
      "Epoch: 001, cost: 8.77, test_acc: 0.8497\n",
      "Epoch: 002, cost: 17.45, test_acc: 0.8379\n",
      "Epoch: 003, cost: 18.28, test_acc: 0.8404\n",
      "Epoch: 004, cost: 9.93, test_acc: 0.8816\n",
      "Epoch: 005, cost: 19.77, test_acc: 0.9224\n",
      "Epoch: 006, cost: 10.29, test_acc: 0.8639\n",
      "Epoch: 007, cost: 23.08, test_acc: 0.9347\n",
      "Epoch: 008, cost: 7.54, test_acc: 0.9229\n",
      "Epoch: 009, cost: 13.26, test_acc: 0.9258\n",
      "Epoch: 010, cost: 19.63, test_acc: 0.9032\n",
      "Epoch: 011, cost: 9.56, test_acc: 0.9072\n",
      "Epoch: 012, cost: 19.78, test_acc: 0.9062\n",
      "Epoch: 013, cost: 14.20, test_acc: 0.9327\n",
      "Epoch: 014, cost: 18.85, test_acc: 0.9219\n",
      "Epoch: 015, cost: 7.35, test_acc: 0.8325\n",
      "Epoch: 016, cost: 24.33, test_acc: 0.9376\n",
      "Epoch: 017, cost: 7.25, test_acc: 0.8944\n",
      "Epoch: 018, cost: 21.88, test_acc: 0.9028\n",
      "Epoch: 019, cost: 7.52, test_acc: 0.8811\n",
      "Epoch: 020, cost: 16.61, test_acc: 0.9244\n",
      "Epoch: 021, cost: 11.97, test_acc: 0.9337\n",
      "Epoch: 022, cost: 15.78, test_acc: 0.8094\n",
      "Epoch: 023, cost: 17.29, test_acc: 0.9386\n",
      "Epoch: 024, cost: 6.56, test_acc: 0.9312\n",
      "Epoch: 025, cost: 15.12, test_acc: 0.9037\n",
      "Epoch: 026, cost: 9.27, test_acc: 0.9425\n",
      "Epoch: 027, cost: 17.62, test_acc: 0.9347\n",
      "Epoch: 028, cost: 11.03, test_acc: 0.8134\n",
      "Epoch: 029, cost: 19.68, test_acc: 0.9391\n",
      "Epoch: 030, cost: 6.63, test_acc: 0.9307\n",
      "Epoch: 031, cost: 15.37, test_acc: 0.9111\n",
      "Epoch: 032, cost: 13.71, test_acc: 0.9361\n",
      "Epoch: 033, cost: 16.65, test_acc: 0.9307\n",
      "Epoch: 034, cost: 8.56, test_acc: 0.9224\n",
      "Epoch: 035, cost: 16.66, test_acc: 0.9425\n",
      "Epoch: 036, cost: 9.58, test_acc: 0.8674\n",
      "Epoch: 037, cost: 10.06, test_acc: 0.9396\n",
      "Epoch: 038, cost: 19.76, test_acc: 0.9371\n",
      "Epoch: 039, cost: 9.00, test_acc: 0.9357\n",
      "Epoch: 040, cost: 13.21, test_acc: 0.9317\n",
      "Epoch: 041, cost: 12.37, test_acc: 0.9352\n",
      "Epoch: 042, cost: 21.29, test_acc: 0.9347\n",
      "Epoch: 043, cost: 7.17, test_acc: 0.9416\n",
      "Epoch: 044, cost: 13.31, test_acc: 0.9337\n",
      "Epoch: 045, cost: 11.84, test_acc: 0.9185\n",
      "Epoch: 046, cost: 10.04, test_acc: 0.9430\n",
      "Epoch: 047, cost: 18.90, test_acc: 0.9386\n",
      "Epoch: 048, cost: 8.32, test_acc: 0.9430\n",
      "Epoch: 049, cost: 17.53, test_acc: 0.9406\n",
      "Epoch: 050, cost: 5.56, test_acc: 0.9430\n",
      "Epoch: 051, cost: 20.55, test_acc: 0.9332\n",
      "Epoch: 052, cost: 5.60, test_acc: 0.9470\n",
      "Epoch: 053, cost: 17.29, test_acc: 0.9425\n",
      "Epoch: 054, cost: 5.91, test_acc: 0.9268\n",
      "Epoch: 055, cost: 20.34, test_acc: 0.9401\n",
      "Epoch: 056, cost: 6.50, test_acc: 0.9249\n",
      "Epoch: 057, cost: 10.32, test_acc: 0.9190\n",
      "Epoch: 058, cost: 9.64, test_acc: 0.9406\n",
      "Epoch: 059, cost: 15.07, test_acc: 0.9533\n",
      "Epoch: 060, cost: 12.95, test_acc: 0.9411\n",
      "Epoch: 061, cost: 9.90, test_acc: 0.9337\n",
      "Epoch: 062, cost: 9.88, test_acc: 0.9391\n",
      "Epoch: 063, cost: 19.21, test_acc: 0.9445\n",
      "Epoch: 064, cost: 6.09, test_acc: 0.9504\n",
      "Epoch: 065, cost: 17.15, test_acc: 0.9376\n",
      "Epoch: 066, cost: 6.91, test_acc: 0.9465\n",
      "Epoch: 067, cost: 8.75, test_acc: 0.9357\n",
      "Epoch: 068, cost: 11.46, test_acc: 0.9538\n",
      "Epoch: 069, cost: 15.76, test_acc: 0.9371\n",
      "Epoch: 070, cost: 10.13, test_acc: 0.9494\n",
      "Epoch: 071, cost: 9.57, test_acc: 0.9337\n",
      "Epoch: 072, cost: 9.22, test_acc: 0.9524\n",
      "Epoch: 073, cost: 16.94, test_acc: 0.9376\n",
      "Epoch: 074, cost: 4.93, test_acc: 0.9538\n",
      "Epoch: 075, cost: 16.62, test_acc: 0.9347\n",
      "Epoch: 076, cost: 4.77, test_acc: 0.9533\n",
      "Epoch: 077, cost: 14.94, test_acc: 0.9347\n",
      "Epoch: 078, cost: 5.81, test_acc: 0.9082\n",
      "Epoch: 079, cost: 10.24, test_acc: 0.9347\n",
      "Epoch: 080, cost: 16.19, test_acc: 0.9465\n",
      "Epoch: 081, cost: 4.78, test_acc: 0.9568\n",
      "Epoch: 082, cost: 11.12, test_acc: 0.9357\n",
      "Epoch: 083, cost: 8.52, test_acc: 0.9347\n",
      "Epoch: 084, cost: 10.54, test_acc: 0.9563\n",
      "Epoch: 085, cost: 10.77, test_acc: 0.9357\n",
      "Epoch: 086, cost: 4.51, test_acc: 0.9563\n",
      "Epoch: 087, cost: 16.03, test_acc: 0.9298\n",
      "Epoch: 088, cost: 6.54, test_acc: 0.9548\n",
      "Epoch: 089, cost: 18.82, test_acc: 0.9406\n",
      "Epoch: 090, cost: 4.84, test_acc: 0.9548\n",
      "Epoch: 091, cost: 17.85, test_acc: 0.9371\n",
      "Epoch: 092, cost: 4.60, test_acc: 0.9499\n",
      "Epoch: 093, cost: 10.34, test_acc: 0.9519\n",
      "Epoch: 094, cost: 10.68, test_acc: 0.9548\n",
      "Epoch: 095, cost: 10.21, test_acc: 0.9352\n",
      "Epoch: 096, cost: 12.89, test_acc: 0.9391\n",
      "Epoch: 097, cost: 5.93, test_acc: 0.9533\n",
      "Epoch: 098, cost: 10.49, test_acc: 0.9514\n",
      "Epoch: 099, cost: 10.34, test_acc: 0.9538\n",
      "Epoch: 100, cost: 10.40, test_acc: 0.9460\n",
      "Epoch: 101, cost: 11.69, test_acc: 0.9548\n",
      "Epoch: 102, cost: 12.97, test_acc: 0.9386\n",
      "Epoch: 103, cost: 6.19, test_acc: 0.9568\n",
      "Epoch: 104, cost: 16.25, test_acc: 0.9347\n",
      "Epoch: 105, cost: 6.09, test_acc: 0.9563\n",
      "Epoch: 106, cost: 12.27, test_acc: 0.9371\n",
      "Epoch: 107, cost: 5.46, test_acc: 0.9587\n",
      "Epoch: 108, cost: 8.72, test_acc: 0.9578\n",
      "Epoch: 109, cost: 14.59, test_acc: 0.9298\n",
      "Epoch: 110, cost: 4.76, test_acc: 0.9563\n",
      "Epoch: 111, cost: 11.29, test_acc: 0.9494\n",
      "Epoch: 112, cost: 7.14, test_acc: 0.9136\n",
      "Epoch: 113, cost: 5.93, test_acc: 0.9578\n",
      "Epoch: 114, cost: 11.99, test_acc: 0.9489\n",
      "Epoch: 115, cost: 9.76, test_acc: 0.9587\n",
      "Epoch: 116, cost: 8.63, test_acc: 0.9450\n",
      "Epoch: 117, cost: 5.10, test_acc: 0.9661\n",
      "Epoch: 118, cost: 9.13, test_acc: 0.9656\n",
      "Epoch: 119, cost: 10.50, test_acc: 0.9612\n",
      "Epoch: 120, cost: 9.04, test_acc: 0.9470\n",
      "Epoch: 121, cost: 4.34, test_acc: 0.9622\n",
      "Epoch: 122, cost: 16.31, test_acc: 0.9420\n",
      "Epoch: 123, cost: 7.91, test_acc: 0.9548\n",
      "Epoch: 124, cost: 4.36, test_acc: 0.9553\n",
      "Epoch: 125, cost: 13.25, test_acc: 0.9504\n",
      "Epoch: 126, cost: 4.29, test_acc: 0.9661\n",
      "Epoch: 127, cost: 9.60, test_acc: 0.9587\n",
      "Epoch: 128, cost: 11.52, test_acc: 0.9548\n",
      "Epoch: 129, cost: 4.64, test_acc: 0.9622\n",
      "Epoch: 130, cost: 9.00, test_acc: 0.9583\n",
      "Epoch: 131, cost: 8.42, test_acc: 0.9519\n",
      "Epoch: 132, cost: 3.67, test_acc: 0.9700\n",
      "Epoch: 133, cost: 8.09, test_acc: 0.9583\n",
      "Epoch: 134, cost: 10.88, test_acc: 0.9563\n",
      "Epoch: 135, cost: 4.88, test_acc: 0.9553\n",
      "Epoch: 136, cost: 7.96, test_acc: 0.9563\n",
      "Epoch: 137, cost: 6.56, test_acc: 0.9558\n",
      "Epoch: 138, cost: 8.72, test_acc: 0.9607\n",
      "Epoch: 139, cost: 9.01, test_acc: 0.9563\n",
      "Epoch: 140, cost: 4.04, test_acc: 0.9627\n",
      "Epoch: 141, cost: 10.40, test_acc: 0.9376\n",
      "Epoch: 142, cost: 6.11, test_acc: 0.9607\n",
      "Epoch: 143, cost: 7.98, test_acc: 0.9583\n",
      "Epoch: 144, cost: 6.25, test_acc: 0.9632\n",
      "Epoch: 145, cost: 9.85, test_acc: 0.9578\n",
      "Epoch: 146, cost: 4.41, test_acc: 0.9553\n",
      "Epoch: 147, cost: 9.98, test_acc: 0.9607\n",
      "Epoch: 148, cost: 4.55, test_acc: 0.9705\n",
      "Epoch: 149, cost: 8.29, test_acc: 0.9509\n",
      "Epoch: 150, cost: 4.74, test_acc: 0.9691\n",
      "Epoch: 151, cost: 5.88, test_acc: 0.9224\n",
      "Epoch: 152, cost: 8.39, test_acc: 0.9592\n",
      "Epoch: 153, cost: 6.79, test_acc: 0.9558\n",
      "Epoch: 154, cost: 9.76, test_acc: 0.9504\n",
      "Epoch: 155, cost: 5.33, test_acc: 0.9533\n",
      "Epoch: 156, cost: 6.52, test_acc: 0.9710\n",
      "Epoch: 157, cost: 8.22, test_acc: 0.9587\n",
      "Epoch: 158, cost: 5.76, test_acc: 0.9602\n",
      "Epoch: 159, cost: 7.66, test_acc: 0.9666\n",
      "Epoch: 160, cost: 4.86, test_acc: 0.9602\n",
      "Epoch: 161, cost: 7.33, test_acc: 0.9332\n",
      "Epoch: 162, cost: 5.01, test_acc: 0.9597\n",
      "Epoch: 163, cost: 7.99, test_acc: 0.9504\n",
      "Epoch: 164, cost: 5.78, test_acc: 0.9666\n",
      "Epoch: 165, cost: 6.22, test_acc: 0.9622\n",
      "Epoch: 166, cost: 4.72, test_acc: 0.9700\n",
      "Epoch: 167, cost: 9.55, test_acc: 0.9499\n",
      "Epoch: 168, cost: 4.31, test_acc: 0.9499\n",
      "Epoch: 169, cost: 5.86, test_acc: 0.9361\n",
      "Epoch: 170, cost: 3.29, test_acc: 0.9720\n",
      "Epoch: 171, cost: 7.26, test_acc: 0.9509\n",
      "Epoch: 172, cost: 5.51, test_acc: 0.9617\n",
      "Epoch: 173, cost: 7.31, test_acc: 0.9524\n",
      "Epoch: 174, cost: 6.02, test_acc: 0.9656\n",
      "Epoch: 175, cost: 6.89, test_acc: 0.9592\n",
      "Epoch: 176, cost: 7.65, test_acc: 0.9627\n",
      "Epoch: 177, cost: 5.88, test_acc: 0.9533\n",
      "Epoch: 178, cost: 3.54, test_acc: 0.9617\n",
      "Epoch: 179, cost: 7.26, test_acc: 0.9587\n",
      "Epoch: 180, cost: 6.47, test_acc: 0.9651\n",
      "Epoch: 181, cost: 5.62, test_acc: 0.9641\n",
      "Epoch: 182, cost: 4.73, test_acc: 0.9661\n",
      "Epoch: 183, cost: 7.35, test_acc: 0.9509\n",
      "Epoch: 184, cost: 3.93, test_acc: 0.9617\n",
      "Epoch: 185, cost: 6.86, test_acc: 0.9548\n",
      "Epoch: 186, cost: 5.71, test_acc: 0.9587\n",
      "Epoch: 187, cost: 5.13, test_acc: 0.9637\n",
      "Epoch: 188, cost: 4.88, test_acc: 0.9720\n",
      "Epoch: 189, cost: 4.55, test_acc: 0.9641\n",
      "Epoch: 190, cost: 4.19, test_acc: 0.9740\n",
      "Epoch: 191, cost: 4.02, test_acc: 0.9730\n",
      "Epoch: 192, cost: 7.04, test_acc: 0.9533\n",
      "Epoch: 193, cost: 4.78, test_acc: 0.9612\n",
      "Epoch: 194, cost: 5.66, test_acc: 0.9602\n",
      "Epoch: 195, cost: 4.60, test_acc: 0.9730\n",
      "Epoch: 196, cost: 4.06, test_acc: 0.9661\n",
      "Epoch: 197, cost: 4.17, test_acc: 0.9710\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 198, cost: 4.45, test_acc: 0.9666\n",
      "Epoch: 199, cost: 4.56, test_acc: 0.9617\n",
      "Epoch: 200, cost: 6.41, test_acc: 0.9710\n",
      "Epoch: 201, cost: 4.54, test_acc: 0.9617\n",
      "Epoch: 202, cost: 4.88, test_acc: 0.9700\n",
      "Epoch: 203, cost: 4.78, test_acc: 0.9720\n",
      "Epoch: 204, cost: 4.14, test_acc: 0.9661\n",
      "Epoch: 205, cost: 4.32, test_acc: 0.9661\n",
      "Epoch: 206, cost: 4.46, test_acc: 0.9661\n",
      "Epoch: 207, cost: 4.09, test_acc: 0.9720\n",
      "Epoch: 208, cost: 6.73, test_acc: 0.9612\n",
      "Epoch: 209, cost: 3.29, test_acc: 0.9646\n",
      "Epoch: 210, cost: 4.03, test_acc: 0.9612\n",
      "Epoch: 211, cost: 6.00, test_acc: 0.9705\n",
      "Epoch: 212, cost: 4.27, test_acc: 0.9720\n",
      "Epoch: 213, cost: 3.81, test_acc: 0.9646\n",
      "Epoch: 214, cost: 4.42, test_acc: 0.9740\n",
      "Epoch: 215, cost: 3.45, test_acc: 0.9627\n",
      "Epoch: 216, cost: 6.30, test_acc: 0.9627\n",
      "Epoch: 217, cost: 4.61, test_acc: 0.9632\n",
      "Epoch: 218, cost: 6.42, test_acc: 0.9646\n",
      "Epoch: 219, cost: 4.71, test_acc: 0.9646\n",
      "Epoch: 220, cost: 4.72, test_acc: 0.9720\n",
      "Epoch: 221, cost: 3.90, test_acc: 0.9632\n",
      "Epoch: 222, cost: 4.89, test_acc: 0.9661\n",
      "Epoch: 223, cost: 4.18, test_acc: 0.9627\n",
      "Epoch: 224, cost: 4.40, test_acc: 0.9700\n",
      "Epoch: 225, cost: 3.68, test_acc: 0.9597\n",
      "Epoch: 226, cost: 4.90, test_acc: 0.9661\n",
      "Epoch: 227, cost: 3.71, test_acc: 0.9602\n",
      "Epoch: 228, cost: 4.75, test_acc: 0.9661\n",
      "Epoch: 229, cost: 3.88, test_acc: 0.9612\n",
      "Epoch: 230, cost: 4.65, test_acc: 0.9661\n",
      "Epoch: 231, cost: 3.50, test_acc: 0.9597\n",
      "Epoch: 232, cost: 4.53, test_acc: 0.9720\n",
      "Epoch: 233, cost: 3.48, test_acc: 0.9627\n",
      "Epoch: 234, cost: 4.22, test_acc: 0.9646\n",
      "Epoch: 235, cost: 4.13, test_acc: 0.9602\n",
      "Epoch: 236, cost: 4.50, test_acc: 0.9710\n",
      "Epoch: 237, cost: 3.68, test_acc: 0.9720\n",
      "Epoch: 238, cost: 3.35, test_acc: 0.9646\n",
      "Epoch: 239, cost: 3.53, test_acc: 0.9705\n",
      "Epoch: 240, cost: 2.84, test_acc: 0.9740\n",
      "Epoch: 241, cost: 3.14, test_acc: 0.9656\n",
      "Epoch: 242, cost: 3.29, test_acc: 0.9651\n",
      "Epoch: 243, cost: 3.17, test_acc: 0.9666\n",
      "Epoch: 244, cost: 3.18, test_acc: 0.9710\n",
      "Epoch: 245, cost: 3.15, test_acc: 0.9745\n",
      "Epoch: 246, cost: 3.23, test_acc: 0.9710\n",
      "Epoch: 247, cost: 4.21, test_acc: 0.9730\n",
      "Epoch: 248, cost: 3.30, test_acc: 0.9720\n",
      "Epoch: 249, cost: 3.26, test_acc: 0.9592\n",
      "Epoch: 250, cost: 3.86, test_acc: 0.9637\n",
      "Epoch: 251, cost: 3.85, test_acc: 0.9676\n",
      "Epoch: 252, cost: 2.89, test_acc: 0.9656\n",
      "Epoch: 253, cost: 2.86, test_acc: 0.9715\n",
      "Epoch: 254, cost: 2.90, test_acc: 0.9745\n",
      "Epoch: 255, cost: 3.01, test_acc: 0.9661\n",
      "Epoch: 256, cost: 2.67, test_acc: 0.9656\n",
      "Epoch: 257, cost: 3.16, test_acc: 0.9745\n",
      "Epoch: 258, cost: 2.66, test_acc: 0.9720\n",
      "Epoch: 259, cost: 1.95, test_acc: 0.9774\n",
      "Epoch: 260, cost: 2.41, test_acc: 0.9750\n",
      "Epoch: 261, cost: 2.03, test_acc: 0.9750\n",
      "Epoch: 262, cost: 2.60, test_acc: 0.9710\n",
      "Epoch: 263, cost: 1.93, test_acc: 0.9769\n",
      "Epoch: 264, cost: 2.58, test_acc: 0.9759\n",
      "Epoch: 265, cost: 2.61, test_acc: 0.9745\n",
      "Epoch: 266, cost: 2.63, test_acc: 0.9715\n",
      "Epoch: 267, cost: 2.74, test_acc: 0.9750\n",
      "Epoch: 268, cost: 2.88, test_acc: 0.9676\n",
      "Epoch: 269, cost: 2.75, test_acc: 0.9750\n",
      "Epoch: 270, cost: 2.97, test_acc: 0.9745\n",
      "Epoch: 271, cost: 2.60, test_acc: 0.9764\n",
      "Epoch: 272, cost: 1.91, test_acc: 0.9769\n",
      "Epoch: 273, cost: 2.45, test_acc: 0.9764\n",
      "Epoch: 274, cost: 3.56, test_acc: 0.9720\n",
      "Epoch: 275, cost: 3.01, test_acc: 0.9661\n",
      "Epoch: 276, cost: 2.52, test_acc: 0.9656\n",
      "Epoch: 277, cost: 3.00, test_acc: 0.9750\n",
      "Epoch: 278, cost: 2.62, test_acc: 0.9750\n",
      "Epoch: 279, cost: 2.43, test_acc: 0.9745\n",
      "Epoch: 280, cost: 2.52, test_acc: 0.9740\n",
      "Epoch: 281, cost: 2.39, test_acc: 0.9745\n",
      "Epoch: 282, cost: 2.33, test_acc: 0.9750\n",
      "Epoch: 283, cost: 2.49, test_acc: 0.9740\n",
      "Epoch: 284, cost: 2.68, test_acc: 0.9750\n",
      "Epoch: 285, cost: 2.55, test_acc: 0.9750\n",
      "Epoch: 286, cost: 1.53, test_acc: 0.9764\n",
      "Epoch: 287, cost: 2.55, test_acc: 0.9715\n",
      "Epoch: 288, cost: 1.86, test_acc: 0.9754\n",
      "Epoch: 289, cost: 2.38, test_acc: 0.9759\n",
      "Epoch: 290, cost: 3.46, test_acc: 0.9720\n",
      "Epoch: 291, cost: 2.78, test_acc: 0.9666\n",
      "Epoch: 292, cost: 2.57, test_acc: 0.9759\n",
      "Epoch: 293, cost: 1.73, test_acc: 0.9774\n",
      "Epoch: 294, cost: 3.12, test_acc: 0.9750\n",
      "Epoch: 295, cost: 2.37, test_acc: 0.9710\n",
      "Epoch: 296, cost: 1.70, test_acc: 0.9759\n",
      "Epoch: 297, cost: 1.46, test_acc: 0.9750\n",
      "Epoch: 298, cost: 1.92, test_acc: 0.9779\n",
      "Epoch: 299, cost: 2.54, test_acc: 0.9759\n"
     ]
    }
   ],
   "source": [
    "# 测试集\n",
    "def testing(ser_W, ser_b):\n",
    "    tf.compat.v1.reset_default_graph()\n",
    "    \n",
    "    x = tf.placeholder(tf.float32, [None, n_features])\n",
    "    y = tf.placeholder(tf.float32, [None, n_class])\n",
    "    \n",
    "    W = tf.Variable(ser_W)\n",
    "    b = tf.Variable(ser_b)\n",
    "    pred = tf.matmul(x, W) + b\n",
    "    \n",
    "    correct_prediction = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))\n",
    "    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))\n",
    "    \n",
    "    # 初始化所有变量\n",
    "    init = tf.global_variables_initializer()\n",
    "\n",
    "    # 训练模型\n",
    "    with tf.Session() as sess:\n",
    "        sess.run(init)\n",
    "        acc = accuracy.eval({x: X_test, y: y_test})\n",
    "    \n",
    "    return acc\n",
    "\n",
    "# 设置模型\n",
    "batch_size = 100\n",
    "n_features = 5\n",
    "n_class = 2\n",
    "\n",
    "EPOCH_NUM = 50 * CLIENT_NUM\n",
    "server_lr = 0.001\n",
    "\n",
    "# 模型参数\n",
    "server_W = np.zeros([n_features, n_class], dtype=np.float32)\n",
    "server_b = np.zeros([n_class], dtype=np.float32)\n",
    "server_model = [server_W, server_b]\n",
    "\n",
    "for epoch in range(EPOCH_NUM):\n",
    "    server_upload_model(server_model, epoch)\n",
    "    \n",
    "    for c_id in range(CLIENT_NUM):\n",
    "        train_model(c_id)\n",
    "    \n",
    "    total_grad_W = None\n",
    "    total_grad_b = None\n",
    "    total_size = 0\n",
    "    total_cost = 0\n",
    "    \n",
    "    updates = server_query_updates(epoch)\n",
    "    for update in updates:\n",
    "        grads, meta = update\n",
    "        grad_W, grad_b = grads\n",
    "        data_size, cost = meta\n",
    "        \n",
    "        total_grad_W = (grad_W * data_size) if (total_grad_W is None) else (total_grad_W + grad_W * data_size)\n",
    "        total_grad_b = (grad_b * data_size) if (total_grad_b is None) else (total_grad_b + grad_b * data_size)\n",
    "        total_size += data_size\n",
    "        total_cost += cost\n",
    "        \n",
    "    total_grad_W /= total_size\n",
    "    total_grad_b /= total_size\n",
    "    total_cost /= CLIENT_NUM\n",
    "    \n",
    "    \n",
    "    # update global model\n",
    "    server_W = server_W - server_lr * total_grad_W\n",
    "    server_b = server_b - server_lr * total_grad_b\n",
    "    server_model = [server_W, server_b]\n",
    "    \n",
    "    test_acc = testing(server_W, server_b)\n",
    "    print(\"Epoch: {:03}, cost: {:.2f}, test_acc: {:.4f}\".format(epoch, total_cost, test_acc))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  },
  "output_auto_scroll": true,
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
